import {Injectable} from "@angular/core";

import {Storage} from '@ionic/storage';
import {Router} from "angular2/router";
import {ContentCardType} from "../model/content-card-type";
import {ContentCardModel} from "../model/content-card-model";
import {ReplyModel} from "../components/reply-list/reply-list";
import {Events} from "ionic-angular";
import {AppHttpService} from "./AppHttpService";
import {EmojiService} from "./EmojiService";
import {CommentType} from "../components/reply-input/comment-type";
import {File} from "ionic-native";
/**
 * Created by jackbranson on 17/3/6.
 */

@Injectable()
export class AppService {
  private token: string;
  private token_exp: number;
  private _username: string;
  private _uid: number;
  private token_ttl: number = 300000;
  private initialized: Promise<boolean> ;
  private domain: string = "http://127.0.0.1:8881";


  constructor(private storage: Storage,
              private events: Events,
              private emojiService: EmojiService,
              private http: AppHttpService) {
    this.initialized = new Promise((resolve, reject) => {
      storage.get('token').then(v => {
        if (v) {
          this.token = v;
          storage.get('token_exp').then(v => {
          this.token_exp = parseInt(v);
          storage.get('username').then(v => {
          this._username = v;
          storage.get('uid').then(v => {
          this._uid = v;
          resolve(true);
          })})});
        }
        else {
          this.token = '';
          this.token_exp = 0;
          this._username = '';
          this._uid = 0;
          resolve(true);
        }
      });
    })
  }

  get username(): Promise<string> {
    return new Promise((resolve, reject) => {
      this.initialized.then(() => {
        resolve(this._username);
      })
    })
  }

  get uid(): Promise<number> {
    return new Promise((resolve, reject) => {
      this.initialized.then(() => {
        resolve(this._uid);
      })
    })
  }

  get isLogin(): Promise<boolean> {
    return new Promise((resolve, reject) => {
      this.initialized.then(() => {
        let now = new Date().getTime();
        resolve(this.token_exp - now > 0);
      })
    });
  }

  private getHeaderToken(): Promise<Object> {
    return new Promise((resolve, reject) => {
      this.isLogin.then((login) => {
        if (login) {
          resolve({Authorization: this.token})
        }
        else {
          resolve({})
        }
      })
    });
  }

  private getParamToken(): Promise<string> {
    return new Promise((resolve, reject) => {
      this.isLogin.then(login => {
        if (login) {
          resolve('token=' + this.token);
        }
        else {
          resolve('');
        }
      })
    })
  }

  startRefresh() {
    setInterval(this.refreshToken, this.token_ttl * 0.8);
  }

  getToken(username: string, password: string): Promise<void> {
    return new Promise((resolve, reject) => {
      this.http.post(this.domain + '/api/v1/get_token', {email: username, password: password}).subscribe(resp => {
        if (resp.status != 200)
        {
          reject(resp.statusText);
          return
        }
        let data = resp.json();
        this.token = data['token'].split('Bearer ')[1];
        this._username = data['username'];
        this._uid = data['uid'];
        this.token_exp = (new Date()).getTime() + this.token_ttl;
        this.storage.set('token', this.token);
        this.storage.set('token_exp', this.token_exp);
        this.storage.set('username', data['username']);
        this.storage.set('uid', data['uid']);
        resolve();
      })
    });

  }

  refreshToken() {
    this.redirectIfNotLogin();
    this.http.put(this.domain + '/api/v1/get_token', {_: 'refresh'}, this.getHeaderToken()).subscribe(resp => {
      let data = resp.json();
      this.token = data['token'].split('Bearer ')[1];
      this.token_exp = (new Date()).getTime() + this.token_ttl;
    })
  }

  redirectIfNotLogin() {
    this.isLogin.then(login => {
      if (!login) {
        this.events.publish('app:unauthenticated');
      }
    })
  }

  private resolveData(data: Array<any>, token: string) {
    let ret: Array<ContentCardModel> = [];
    data.map((value, idx) => {
      let content_type: ContentCardType;
      if (value['content_type'] == 'mb')
      {
        content_type = ContentCardType.MessageBoard;
      }
      else if (value['content_type'] == 'st')
      {
        content_type = ContentCardType.Story;
      }
      let comments: Array<ReplyModel> = [];
      value['comments'].map((value, idx) => {
        let content = this.emojiService.escapeEmojiToEmojiElement(value['content']);
        comments.push(new ReplyModel(value['id'], content, value['comment_username'], value['comment_uid'], new Date(value['created_at']), value['comment_reply_uid'], value['comment_reply_username'], value['comment_type']));
      });
      let img_urls = value['img_urls'].map(value => {
        return `${this.domain}/api/v1/photo/${value}?token=${token}`;
      });
      let content = this.emojiService.escapeEmojiToEmojiElement(value['content']);
      ret.push(new ContentCardModel(content_type, value['id'], value['id']+'_'+Math.random().toString(), value['subject'], content, value['uid'], value['username'], img_urls, new Date(value['created_at']), new Date(value['updated_at']), comments));
    });


    return ret;
  }

  private getContent(contentType: ContentCardType): Promise<Array<ContentCardModel>> {
    return new Promise<Array<ContentCardModel>>((resolve, reject) => {
      this.getHeaderToken().then(header_token => {
        let api = '';
        if (contentType == ContentCardType.Story) {
          api = 'story';
        }
        else if (contentType == ContentCardType.MessageBoard) {
          api = 'message';
        }
        else if (contentType == ContentCardType.Index)
        {
          api = 'index';
        }
        this.http.get(this.domain + '/api/v2/' + api, header_token).subscribe(resp => {
          let data = resp.json();
          let ret = this.resolveData(data, this.token);
          resolve(ret);
        })
      });
    });
  }

  getMessageBoard() {
    return this.getContent(ContentCardType.MessageBoard);
  }

  getStory() {
    return this.getContent(ContentCardType.Story);
  }

  getTimeline() {
    return this.getContent(ContentCardType.Index);
  }

  replyPost(contentType: ContentCardType, post_id: number, content: string, commentType: CommentType, additionText: string = ''): Promise<any> {
    let apis = new Map<ContentCardType, string>([
      [ContentCardType.Story, 'story'],
      [ContentCardType.MessageBoard, 'message']
    ]);
    let api = apis.get(contentType);
    return new Promise((resolve, reject) => {
      if (commentType == CommentType.VoiceComment)
      {
        this.getHeaderToken().then(token => {
          this.http.put(this.domain + '/api/v1/voice', {
            to_post: post_id,
            content: content
          }, token).subscribe(resp => {
            if (resp.status !== 200)
            {
              reject(resp.statusText);
              return
            }
            let upload_token = resp.json()['token'];

          })
        })
      }
      else
      {
        this.getHeaderToken().then(token => {
          this.http.post(this.domain + '/api/v1/comment/' + api, {pid: post_id, content: content, comment_type: commentType, addition_content: additionText}, token).subscribe(resp => {
            if (resp.status != 200)
            {
              reject(resp.statusText);
              return
            }
            resolve({commentId: resp.json()['comment_id'], additionalText: additionText})
          })
        });
      }

    })
  }
}
